﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Caliburn.Micro;
using Csla;
using Csla.Rules.CommonRules;
using Agnes.Core;
using System.IO;
using System.Xml.Linq;
using Ionic.Zip;
using ICSharpCode.Core;

namespace Agnes.Core
{
    /// <summary>
    /// Agnes 解决方案
    /// </summary>
    public class AgnesSln : ModelBase<AgnesSln>
    {
        #region Csla Property

        /// <summary>
        /// 包括扩展名:*.agsln
        /// </summary>
        public static readonly PropertyInfo<string> SlnNameProperty = RegisterProperty<string>(c => c.SlnName);
       
        /// <summary>
        /// 解决方案名称
        /// </summary>
        public string SlnName
        {
            get { return GetProperty(SlnNameProperty); }
            set { SetProperty(SlnNameProperty, value); }
        }

        public static readonly PropertyInfo<string> TempDirProperty = RegisterProperty<string>(c => c.TempDir);
        /// <summary>
        /// 临时解压路径
        /// </summary>
        public string TempDir
        {
            get { return GetProperty(TempDirProperty); }
            private set { LoadProperty(TempDirProperty, value); }
        }

        /// <summary>
        /// 如果不设置密码 让他等于""
        /// </summary>
        public static readonly PropertyInfo<string> PasswordProperty = RegisterProperty<string>(c => c.Password);
        public string Password
        {
            get { return GetProperty(PasswordProperty); }
            set { SetProperty(PasswordProperty, value); }
        }

        /// <summary>
        /// 解决方案存放路径,不包含文件名
        /// </summary>
        public static readonly PropertyInfo<string> LocatedDirProperty = RegisterProperty<string>(c => c.LocatedDir);
        public string LocatedDir
        {
            get { return GetProperty(LocatedDirProperty); }
            set { SetProperty(LocatedDirProperty, value); }
        }

        /// <summary>
        /// 包括文件名的全路径
        /// </summary>
        public string FullName
        {
            get
            {
                return Path.Combine(LocatedDir, SlnName + ".agsln");
            }
        }

        #endregion

        #region Csla Method

        /// <summary>
        /// DoCreate
        /// </summary>
        /// <param name="createParam"></param>
        protected override void DoCreate(object createParam)
        {
            base.DoCreate(createParam);
            using (BypassPropertyChecks)
            {
                int c = 0;

                if (Directory.Exists(PropertyService.Get("DefaultSlnDir")))
                    c = Directory.GetFiles(PropertyService.Get("DefaultSlnDir"), "*.agsln").Count();
                SlnName = "DefaultSln_" + c.ToString();

                //Debug
                TempDir = Path.Combine(AgnesServiceManager.RootPath, "DebugSlnTempDir", "DebugTempDir_" + SlnName);

                //Release
                //TempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

                Password = "";
                LocatedDir = PropertyService.Get("DefaultSlnDir");
            }
        }

        /// <summary>
        /// DoFetch
        /// </summary>
        /// <param name="fetchParam"></param>
        protected override void DoFetch(object fetchParam)
        {
            XElement el = fetchParam as XElement;
            base.DoFetch(fetchParam);
            using (BypassPropertyChecks)
            {
                SlnName = el.Attribute("SlnName").Value;
                TempDir = Path.Combine(AgnesServiceManager.RootPath, "DebugSlnTempDir", "DebugTempDir_" + SlnName);
                Password = el.Attribute("Password").Value;
                LocatedDir = el.Attribute("LocatedDir").Value;
            }
        }

        public void SaveToXml(Action<XElement> saveFunc)
        {
            saveFunc(GetXml());
            DataPortal_Update();
        }

        private XElement GetXml()
        {
            XElement el = new XElement("AgnesSln",
                new XAttribute("SlnName", SlnName),
                new XAttribute("Password", Password),
                new XAttribute("LocatedDir", LocatedDir));

            return el;
        }


        #endregion

        #region Validation

        protected override void AddBusinessRules()
        {
            base.AddBusinessRules();

            AddSlnNameRule();
            AddLocatedDirRule();
        }

        private void AddSlnNameRule()
        {
            var r = new Lambda(SlnNameProperty, t =>
                {
                    AgnesSln h = t.Target as AgnesSln;
                    if (h.SlnName.Length == 0)
                        t.AddErrorResult("文件名不能为空");
                    foreach (char i in Path.GetInvalidFileNameChars())
                    {
                        if (h.SlnName.IndexOf(i) != -1)
                            t.AddErrorResult("该文件名不符合Windows文件命名!");
                    }
                    //Debug
                    h.TempDir = Path.Combine(AgnesServiceManager.RootPath, 
                        "DebugSlnTempDir", "DebugTempDir_" + h.SlnName);
                });

            BusinessRules.AddRule(r);
        }

        private void AddLocatedDirRule()
        {
            var r = new Lambda(LocatedDirProperty, t =>
            {
                AgnesSln h = t.Target as AgnesSln;
                if (!Directory.Exists(h.LocatedDir))
                    t.AddErrorResult("目标路径不存在");
            });

            BusinessRules.AddRule(r);
        }

        #endregion

        #region Method

        /// <summary>
        /// 初始化解决方案目录,当创建解决方案时候调用.
        /// </summary>
        public void InitializeSln()
        {
            //Debug
            TempDir = Path.Combine(AgnesServiceManager.RootPath, "DebugSlnTempDir", "DebugTempDir_" + SlnName);

            if (!Directory.Exists(TempDir))
            {
                Directory.CreateDirectory(TempDir);
                XElement el = GetXml();
                el.Save(Path.Combine(TempDir, SlnName + ".xml"));
            }
        }

        /// <summary>
        /// 将解决方案打包
        /// </summary>
        public void Package()
        {
            if (!Directory.Exists(TempDir))
                InitializeSln();

            using (ZipFile zf = new ZipFile())
            {
                if (Password.Length != 0)
                    zf.Password = Password;

                zf.AddDirectory(TempDir);

                string locatedpath = LocatedDir;
                if (LocatedDir.LastIndexOf("\\") != LocatedDir.Length - 1)
                    locatedpath += "\\";
                zf.Save(Path.Combine(locatedpath, SlnName + ".agsln"));
            }
        }

        /// <summary>
        /// 解压解决方案
        /// </summary>
        /// <param name="fullName"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public static AgnesSln UnPackage(string fullName, string pwd = "")
        {
            AgnesSln sln = AgnesSln.CreateAsChild();
            sln.SlnName = fullName.Substring(fullName.LastIndexOf("\\") + 1)
                .Substring(0, fullName.Substring(fullName.LastIndexOf("\\") + 1).LastIndexOf("."));
            sln.Password = pwd;
            sln.LocatedDir = fullName.Substring(0, fullName.LastIndexOf("\\"));

            using (ZipFile zip = ZipFile.Read(fullName))
            {
                if (Directory.Exists(sln.TempDir))
                    Directory.Delete(sln.TempDir, true);

                foreach (ZipEntry e in zip)
                    e.ExtractWithPassword(sln.TempDir, ExtractExistingFileAction.OverwriteSilently, sln.Password);
                
                XElement el = XElement.Load(Path.Combine(sln.TempDir, sln.SlnName + ".xml"));
                sln = AgnesSln.FetchAsChild(el);
            }

            return sln;
        }

        #endregion
    }
}
